package your.rfgui.application.controller;

import javax.faces.bean.ManagedBean;
import javax.faces.bean.SessionScoped;
import org.apache.log4j.Logger;
import org.richfaces.event.DropEvent;
import your.rfgui.application.data.MyParentChildEntity;
import your.rfgui.application.data.MyParentChildService;
import your.rfgui.extgui.controller.intf.TreeSelectionChangedListener;
import your.rfgui.extgui.controller.table.ParentChildTableController;
import your.rfgui.extgui.controller.tree.ParentChildTreeController;
import your.rfgui.extgui.controller.tree.TreeViewNode;
import your.rfgui.extgui.controller.tree.data.LabelDataItem;
import your.rfgui.extgui.service.intf.GuiParentChildService;

/**
 * The controller holding and controlling a tree, a table and an editing gui components
 */
@ManagedBean(name = "bean")
@SessionScoped
public class MyBeanController implements TreeSelectionChangedListener {

   private static final Logger log = Logger.getLogger(MyBeanController.class);
   /** entity service */
   private GuiParentChildService<MyParentChildEntity> entityService = MyParentChildService.getInstance();
   /** label of top level tree node */
   private static final String treeRootNodeLabel = "Tree Root Node";
   /** tree controller */
   private ParentChildTreeController<MyParentChildEntity> tree = new ParentChildTreeController<MyParentChildEntity>(
           treeRootNodeLabel, entityService);
   /** table controller */
   private ParentChildTableController<MyParentChildEntity> table = new ParentChildTableController<MyParentChildEntity>(
           entityService);

   public MyBeanController() {
      /** tree selection changes are forwarded to this controller */
      tree.setSelectionChangeListener(this);
   }

   /**
    * Retrieve the table GUI component
    */
   public ParentChildTableController<MyParentChildEntity> getTable() {
      return table;
   }

   /**
    * Retrieve the tree GUI component
    */
   public ParentChildTreeController<MyParentChildEntity> getTree() {
      return tree;
   }

   /**
    * Tree selection has changed, change the table list parent
    * @param treeViewNode the new selected tree view node
    */
   public void treeSelectionChanged(TreeViewNode treeViewNode) {
      /** if the selected node is a leaf */
      if (treeViewNode.isLeaf()) {
         /** set the parent as the list parent in the table component */
         table.setListParent(treeViewNode.getParent().getDataItem());
         /** and select the item selected in the tree component */
         table.setSelectedDataItem(treeViewNode.getDataItem());
      } else {
         /** set the selected item in the tree component */
         table.setListParent(treeViewNode.getDataItem());
      }
   }

   // dummy
   public void command() {
      log.info("command");
   }

   /**
    * Used by view. Called after drag and drop mouse operation.
    * <rich:dropTarget ... dropListener="#{bean.processDrop}" ... />
    * @param event
    */
   public void processDrop(DropEvent event) {
      Object source = event.getDragValue();
      Object target = event.getDropValue();
      log.info("processDrop - source: " + source + " target: " + target);

      /** Evaluate source: entity to be moved */
      assert (source != null);
      assert (source instanceof MyParentChildEntity);
      MyParentChildEntity entityMoved = (MyParentChildEntity) source;

      /** Evaluate target: new parent of the moved entity */
      assert (target != null);
      if (target instanceof LabelDataItem) {
         /** moved to root item */
         entityMoved.setParent(null);
      } else {
         /** moved to other entity */
         assert (target instanceof MyParentChildEntity);
         MyParentChildEntity newParent = (MyParentChildEntity) target;
         /** check for moving to own child or to its own parent */
         if (isIndirectChildOf(newParent, entityMoved)
                 || newParent.equals(entityMoved.getParent())) {
            log.info("move supressed to child/subchildren or own parent");
            return;
         }
         entityMoved.setParent(newParent);
      }

      /** update parent relationship */
      entityService.update(entityMoved);
      /** re-populate tree */
      tree.populate();
      /** reload table entries under listParent */
      table.setListParent(table.getListParent());
   }

   /**
    * Helper method. Checks if the testChildren entity is a child or sub-child of the testParent entity
    */
   private boolean isIndirectChildOf(MyParentChildEntity testChildren, MyParentChildEntity testParent) {
      /** step upwards to the root and check if entityMoved entity is found */
      while (testChildren != null && !testChildren.equals(testParent)) {
         testChildren = testChildren.getParent();
      }
      return testChildren != null;
   }
}
